﻿using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Net;
using System.Windows.Media;
using CuteRibs.D3Armory.Models;
using CuteRibs.D3Armory.Resources;
using CuteRibs.MVVMLib;
using Newtonsoft.Json;

namespace CuteRibs.D3Armory.ViewModels
{
	public class HeroViewModel : ViewModelBase
	{
		private bool refresh;
		private Hero hero;
		private SolidColorBrush classNameColor;
		private string itemBackgroundUri;

		public Hero Hero
		{
			get { return this.hero; }
			set
			{
				if (this.hero != value)
				{
					this.hero = value;
					this.NotifyPropertyChanged("Hero");
					this.SetViewModel();
				}
			}
		}

		public SolidColorBrush ClassNameColor
		{
			get { return this.classNameColor; }
			set
			{
				if (this.classNameColor != value)
				{
					this.classNameColor = value;
					this.NotifyPropertyChanged("ClassNameColor");
				}
			}
		}

		public string ItembackgroundUri
		{
			get { return this.itemBackgroundUri; }
			set
			{
				if (this.itemBackgroundUri != value)
				{
					this.itemBackgroundUri = value;
					this.NotifyPropertyChanged("ItembackgroundUri");
				}
			}
		}

		public ObservableCollection<HeroItemViewModel> Items { get; set; }

		public ObservableCollection<SkillViewModel> SkillSets { get; set; }

		public ObservableCollection<FollowerViewModel> Followers { get; set; }

		public HeroViewModel() : this(null, false) { }

		public HeroViewModel(Hero hero, bool refresh)
			: base()
		{
			this.refresh = refresh;
			this.Hero = hero;
		}

		private void SetViewModel()
		{
			if (this.Hero == null)
			{
				return;
			}

			this.ClassNameColor = new SolidColorBrush(this.Hero.Hardcore ? Helper.ParseColor(0xFF0000) : Helper.ParseColor(0x4E4536));
			this.ItembackgroundUri = App.GetItemBackgroundUri(this.Hero.Class.Id, this.Hero.Gender);
			this.SetActiveSkills(this.Hero.Skills);
			this.SetFollowers(this.Hero.Followers);

			if (!App.IsDesignMode)
			{
				this.SetItems(this.Hero.Items);
			}

			this.refresh = false;
		}

		private void SetActiveSkills(Hero.HeroSkills skills)
		{
			if (this.SkillSets == null)
			{
				this.SkillSets = new ObservableCollection<SkillViewModel>();
			}
			else
			{
				this.SkillSets.Clear();
			}

			for (int i = 0; i < skills.Active.Length; i++)
			{
				this.SkillSets.Add(new SkillViewModel(i, skills.Active[i]));
			}

			for (int i = 0; i < skills.Passive.Length; i++)
			{
				this.SkillSets.Add(new SkillViewModel(-1, skills.Passive[i]));
			}
		}

		private void SetFollowers(Hero.HeroFollowers followers)
		{
			if (this.Followers == null)
			{
				this.Followers = new ObservableCollection<FollowerViewModel>();
			}
			else
			{
				this.Followers.Clear();
			}

			FollowerViewModel follower;

			if (followers.Templar != null)
			{
				follower = new FollowerViewModel(followers.Templar, refresh);
				follower.BackgroundUri = "/Resources/Images/follower_templar.jpg";
				this.Followers.Add(follower);
			}

			if (followers.Scoundrel != null)
			{
				follower = new FollowerViewModel(followers.Scoundrel, refresh);
				follower.BackgroundUri = "/Resources/Images/follower_scoundrel.jpg";
				this.Followers.Add(follower);
			}

			if (followers.Enchantress != null)
			{
				follower = new FollowerViewModel(followers.Enchantress, refresh);
				follower.BackgroundUri = "/Resources/Images/follower_enchantress.jpg";
				this.Followers.Add(follower);
			}
		}

		private async void SetItems(Hero.HeroItems items)
		{
			if (this.Items == null)
			{
				this.Items = new ObservableCollection<HeroItemViewModel>();
			}
			else
			{
				this.Items.Clear();
			}

			foreach (var itemBrief in items.AllItems)
			{
				try
				{
					Item item = null;

					if (refresh)
					{
						item = await App.GetItem(itemBrief);
					}
					else
					{
						item = await App.LoadItem(itemBrief);
					}

					if (!string.IsNullOrEmpty(hero.ErrorCode))
					{
						App.ShowAlert(string.Format("{0}: {1}", hero.ErrorCode, hero.ErrorReason));
						return;
					}
					else
					{
						this.Items.Add(new HeroItemViewModel(item));
					}
				}
				catch (Exception ex)
				{
					if (ex is WebException || ex is JsonReaderException)
					{
						App.ShowAlert(AppRes.MsgDataAccessError);
					}
					else
					{
						App.ShowError(new AppException(ex, itemBrief.TooltipParams));
					}

					return;
				}
			}
		}
	}

	public class SmallHeroViewModel : ViewModelBase
	{
		private string name;
		private ushort level;
		private SolidColorBrush nameColor;
		private string lastUpdated;
		private string portraitUri;

		public string Name
		{
			get { return this.name; }
			set
			{
				if (this.name != value)
				{
					this.name = value;
					this.NotifyPropertyChanged("Name");
				}
			}
		}

		public ushort Level
		{
			get { return this.level; }
			set
			{
				if (this.level != value)
				{
					this.level = value;
					this.NotifyPropertyChanged("Level");
				}
			}
		}

		public SolidColorBrush NameColor
		{
			get { return this.nameColor; }
			set
			{
				if (this.nameColor != value)
				{
					this.nameColor = value;
					this.NotifyPropertyChanged("NameColor");
				}
			}
		}

		public string LastUpdated
		{
			get { return this.lastUpdated; }
			set
			{
				if (this.lastUpdated != value)
				{
					this.lastUpdated = value;
					this.NotifyPropertyChanged("LastUpdated");
				}
			}
		}

		public string PortraitUri
		{
			get { return this.portraitUri; }
			set
			{
				if (this.portraitUri != value)
				{
					this.portraitUri = value;
					this.NotifyPropertyChanged("PortraitUri");
				}
			}
		}

		public SmallHeroViewModel(HeroBrief hero)
		{
			this.Name = hero.Name;
			this.Level = hero.Level;
			this.NameColor = new SolidColorBrush(hero.Hardcore ? Colors.Red : Helper.ParseColor(0xD96500));
			this.LastUpdated = hero.LastUpdated.ToString(CultureInfo.CurrentUICulture);
			this.PortraitUri = GetProtraitUri(hero);
		}

		private static string GetProtraitUri(HeroBrief hero)
		{
			string className = hero.Class.Id.Replace("-", string.Empty);
			string genderName = hero.Gender == 0 ? "male" : "female";
			return string.Format("/Resources/Images/{0}_{1}.png", className, genderName);
		}
	}

	public class NormalHeroViewModel : ViewModelBase
	{
		private uint id;
		private string name;
		private ushort level;
		private SolidColorBrush nameColor;
		private string lastUpdated;
		private SpriteImageViewModel frameViewModel;
		private SpriteImageViewModel portraitViewModel;

		public uint Id
		{
			get { return this.id; }
			set
			{
				if (this.id != value)
				{
					this.id = value;
					this.NotifyPropertyChanged("Id");
				}
			}
		}

		public string Name
		{
			get { return this.name; }
			set
			{
				if (this.name != value)
				{
					this.name = value;
					this.NotifyPropertyChanged("Name");
				}
			}
		}

		public ushort Level
		{
			get { return this.level; }
			set
			{
				if (this.level != value)
				{
					this.level = value;
					this.NotifyPropertyChanged("Level");
				}
			}
		}

		public SolidColorBrush NameColor
		{
			get { return this.nameColor; }
			set
			{
				if (this.nameColor != value)
				{
					this.nameColor = value;
					this.NotifyPropertyChanged("NameColor");
				}
			}
		}

		public string LastUpdated
		{
			get { return this.lastUpdated; }
			set
			{
				if (this.lastUpdated != value)
				{
					this.lastUpdated = value;
					this.NotifyPropertyChanged("LastUpdated");
				}
			}
		}

		public SpriteImageViewModel FrameViewModel
		{
			get { return this.frameViewModel; }
			set
			{
				if (this.frameViewModel != value)
				{
					this.frameViewModel = value;
					this.NotifyPropertyChanged("FrameViewModel");
				}
			}
		}

		public SpriteImageViewModel ProtraitViewModel
		{
			get { return this.portraitViewModel; }
			set
			{
				if (this.portraitViewModel != value)
				{
					this.portraitViewModel = value;
					this.NotifyPropertyChanged("ProtraitViewModel");
				}
			}
		}

		public NormalHeroViewModel(HeroBrief hero)
		{
			this.Id = hero.Id;
			this.Name = hero.Name;
			this.Level = hero.Level;
			this.NameColor = new SolidColorBrush(hero.Hardcore ? Colors.Red : Helper.ParseColor(0xD96500));
			this.LastUpdated = hero.LastUpdated.ToString(CultureInfo.CurrentUICulture);
			this.FrameViewModel = GetFrameViewModel(hero.Hardcore);
			this.ProtraitViewModel = GetProtraitViewModel(hero);
		}

		private static SpriteImageViewModel GetFrameViewModel(bool hardcore)
		{
			double width = 97d;
			double height = 105d;
			double x = hardcore ? 103d : 0;
			double y = 248d;
			return new SpriteImageViewModel(x, y, width, height);
		}

		private static SpriteImageViewModel GetProtraitViewModel(HeroBrief hero)
		{
			double width = 83d;
			double height = 66d;
			double x = hero.Gender == 0 ? 0d : 83d;
			double y = 0d;

			switch (hero.Class.Id)
			{
				case "demon-hunter":
					y = 66d;
					break;
				case "monk":
					y = 132d;
					break;
				case "witch-doctor":
					y = 198d;
					break;
				case "wizard":
					y = 264d;
					break;
				case "barbarian":
				default:
					y = 0d;
					break;
			}

			return new SpriteImageViewModel(x, y, width, height);
		}
	}

	public class LargeHeroViewModel : ViewModelBase
	{
		private uint id;
		private string name;
		private ushort level;
		private SolidColorBrush nameColor;
		private string lastUpdated;
		private SpriteImageViewModel frameViewModel;
		private SpriteImageViewModel portraitViewModel;

		public uint Id
		{
			get { return this.id; }
			set
			{
				if (this.id != value)
				{
					this.id = value;
					this.NotifyPropertyChanged("Id");
				}
			}
		}

		public string Name
		{
			get { return this.name; }
			set
			{
				if (this.name != value)
				{
					this.name = value;
					this.NotifyPropertyChanged("Name");
				}
			}
		}

		public ushort Level
		{
			get { return this.level; }
			set
			{
				if (this.level != value)
				{
					this.level = value;
					this.NotifyPropertyChanged("Level");
				}
			}
		}

		public SolidColorBrush NameColor
		{
			get { return this.nameColor; }
			set
			{
				if (this.nameColor != value)
				{
					this.nameColor = value;
					this.NotifyPropertyChanged("NameColor");
				}
			}
		}

		public string LastUpdated
		{
			get { return this.lastUpdated; }
			set
			{
				if (this.lastUpdated != value)
				{
					this.lastUpdated = value;
					this.NotifyPropertyChanged("LastUpdated");
				}
			}
		}

		public SpriteImageViewModel FrameViewModel
		{
			get { return this.frameViewModel; }
			set
			{
				if (this.frameViewModel != value)
				{
					this.frameViewModel = value;
					this.NotifyPropertyChanged("FrameViewModel");
				}
			}
		}

		public SpriteImageViewModel ProtraitViewModel
		{
			get { return this.portraitViewModel; }
			set
			{
				if (this.portraitViewModel != value)
				{
					this.portraitViewModel = value;
					this.NotifyPropertyChanged("ProtraitViewModel");
				}
			}
		}

		public LargeHeroViewModel(HeroBrief hero)
		{
			this.Id = hero.Id;
			this.Name = hero.Name;
			this.Level = hero.Level;
			this.NameColor = new SolidColorBrush(hero.Hardcore ? Colors.Red : Helper.ParseColor(0xD96500));
			this.LastUpdated = hero.LastUpdated.ToString(CultureInfo.CurrentUICulture);
			this.FrameViewModel = GetFrameViewModel(hero.Hardcore);
			this.ProtraitViewModel = GetProtraitViewModel(hero);
		}

		private static SpriteImageViewModel GetFrameViewModel(bool hardcore)
		{
			double width = 190d;
			double height = 205d;
			double x = 526d;
			double y = hardcore ? 205d : 0;
			return new SpriteImageViewModel(x, y, width, height);
		}

		private static SpriteImageViewModel GetProtraitViewModel(HeroBrief hero)
		{
			double width = 168d;
			double height = 130d;
			double x = hero.Gender == 0 ? 0d : 168d;
			double y = 0d;

			switch (hero.Class.Id)
			{
				case "demon-hunter":
					y = 130d;
					break;
				case "monk":
					y = 260d;
					break;
				case "witch-doctor":
					y = 390d;
					break;
				case "wizard":
					y = 520d;
					break;
				case "barbarian":
				default:
					y = 0d;
					break;
			}

			return new SpriteImageViewModel(x, y, width, height);
		}
	}
}
